package com.zhike.api.exception;

import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.ResponseBody;
import org.springframework.web.bind.annotation.ResponseStatus;
import org.springframework.web.bind.annotation.RestControllerAdvice;

import com.zhike.common.enums.ResultCode;
import com.zhike.common.exception.ZkimException;

import java.io.ByteArrayOutputStream;
import java.io.PrintStream;

import org.springframework.http.HttpStatus;
import cn.dev33.satoken.exception.DisableServiceException;
import cn.dev33.satoken.exception.NotHttpBasicAuthException;
import cn.dev33.satoken.exception.NotLoginException;
import cn.dev33.satoken.exception.NotPermissionException;
import cn.dev33.satoken.exception.NotRoleException;
import cn.dev33.satoken.util.SaResult;
import lombok.extern.slf4j.Slf4j;

@ResponseBody
@RestControllerAdvice
@Slf4j
public class GlobalExceptionHandler {

    // 拦截：未登录异常
    @ExceptionHandler(NotLoginException.class)
    public SaResult handlerException(NotLoginException nle) {
        nle.printStackTrace();

        // 判断场景值，定制化异常信息
        String message = "";
        int code = ResultCode.FAIL.code();
        if (nle.getType().equals(NotLoginException.NOT_TOKEN)) {
            message = ResultCode.SYS_SA_NO_TOKEN.message();
            code = ResultCode.SYS_SA_NO_TOKEN.code();
        } else if (nle.getType().equals(NotLoginException.INVALID_TOKEN)) {
            message = ResultCode.SYS_SA_INVALID_TOKEN.message();
            code = ResultCode.SYS_SA_INVALID_TOKEN.code();
        } else if (nle.getType().equals(NotLoginException.TOKEN_TIMEOUT)) {
            message = ResultCode.SYS_SA_TOKEN_TIMEOUT.message();
            code = ResultCode.SYS_SA_TOKEN_TIMEOUT.code();
        } else if (nle.getType().equals(NotLoginException.BE_REPLACED)) {
            message = ResultCode.SYS_SA_BE_REPLACED.message();
            code = ResultCode.SYS_SA_BE_REPLACED.code();
        } else if (nle.getType().equals(NotLoginException.KICK_OUT)) {
            message = ResultCode.SYS_SA_KICK_OUT.message();
            code = ResultCode.SYS_SA_KICK_OUT.code();
        } else if (nle.getType().equals(NotLoginException.TOKEN_FREEZE)) {
            message = ResultCode.SYS_SA_TOKEN_FREEZE.message();
            code = ResultCode.SYS_SA_TOKEN_FREEZE.code();
        } else if (nle.getType().equals(NotLoginException.NO_PREFIX)) {
            message = ResultCode.SYS_SA_NO_PREFIX.message();
            code = ResultCode.SYS_SA_NO_PREFIX.code();
        } else {
            message = ResultCode.SYS_SA_NO_SESSION.message();
            code = ResultCode.SYS_SA_NO_SESSION.code();
        }
        return SaResult.code(code).setMsg(message);
    }

    // 拦截：缺少权限异常
    @ExceptionHandler(NotPermissionException.class)
    public SaResult handlerException(NotPermissionException e) {
        log.error("{}", e.getPermission());
        return SaResult.error("缺少权限：" + e.getPermission());
    }

    // 拦截：缺少角色异常
    @ExceptionHandler(NotRoleException.class)
    public SaResult handlerException(NotRoleException e) {
        e.printStackTrace();
        return SaResult.error("缺少角色：" + e.getRole());
    }

    // 拦截：Http Basic 校验失败异常
    @ExceptionHandler(NotHttpBasicAuthException.class)
    public SaResult handlerException(NotHttpBasicAuthException e) {
        e.printStackTrace();
        return SaResult.error(e.getMessage());
    }

    // 拦截：服务封禁异常
    @ExceptionHandler(DisableServiceException.class)
    public SaResult handlerException(DisableServiceException e) {
        e.printStackTrace();
        return SaResult.error(
                "当前账号 " + e.getService() + " 服务已被封禁 (level=" + e.getLevel() + ")：" + e.getDisableTime() + "秒后解封");
    }

    // 拦截：其它所有异常
    @ExceptionHandler(Exception.class)
    public SaResult handlerException(Exception e) {
        e.printStackTrace();
        if (e instanceof ZkimException) {
            ZkimException ee = (ZkimException) e;
            return SaResult.code(ee.getCode()).setMsg(ee.getMessage());
        }
        ByteArrayOutputStream out = new ByteArrayOutputStream();
        PrintStream pout = new PrintStream(out);
        e.printStackTrace(pout);
        String ret = new String(out.toByteArray());
        pout.close();
        try {
            out.close();
        } catch (Exception ex) {
            ex.printStackTrace();
        }
        return SaResult.code(ResultCode.OTHER_ERROR.code()).setMsg(ret);
    }

    /**
     * Spring Framework（尤其是 Spring Web MVC 和 Spring Boot 应用程序中）处理 HTTP 请求时抛出的一个异常
     * 
     * @param e
     * @return
     */
    @ExceptionHandler(HttpMessageNotReadableException.class)
    public SaResult handlerHttpRequestException(HttpMessageNotReadableException e) {
        log.error("{}", e.getMessage());
        return SaResult.code(ResultCode.SYS_REQPARAMS.code()).setMsg(e.getMessage());
    }

    @ResponseStatus(HttpStatus.BAD_REQUEST)
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public SaResult handleValidationExceptions(MethodArgumentNotValidException ex) {
        log.error("{}", ex.getBindingResult().toString());
        return SaResult.code(ResultCode.SYS_ARG_VALID.code()).setMsg(ex.getMessage());
    }
}
